# distribution/hw03/modMonomial.py              David MacQuigg  ece373  10/15/07

from modCloneable import Cloneable

class Monomial(Cloneable):
    '''A monomial is a special polynomial of size 1.  Each monomial consists of
    a single exponent value, and a single coefficient.  The exponent N, is in
    the N0 (Countable numbers, plus 0).  The coefficient a, is in the set of
    Real numbers.'''

    def __init__(self, exp=0, coeff=0.0):
        if type(coeff) not in (float, complex):                     # [1]
            raise TypeError, "coefficient must be float or complex"
        if type(exp) not in (int, long):
            raise TypeError, "exp must be int or long"
        if exp < 0:
            raise ValueError, "exp must be non-negative"
        self._coeff = coeff
        self._exp = exp

    def __str__(self):
        '''Returns a string, formatted as ax^N.
        >>> print m0, m1, m2
        1.0x^0 1.1x^1 2.2x^2
        >>> print m3
        (3.3+4j)x^3
        '''
        return "%sx^%s" % (self._coeff, self._exp)

    def clone(self):
        '''Make a new Monomial with the same parameters.
        >>> m3c = m3.clone()
        '''
        return Monomial(self._exp, self._coeff)

# Setters and getters to access private data

    def setCoefficient(self, coeff):
        assert type(coeff) in (float, complex)                      # [2]
        self._coeff = coeff

    def getCoefficient(self):
        return self._coeff

    def setExponent(self, exp):
        assert type(exp) in (int, long)                             # [2]
        assert exp >= 0
        self._exp = exp

    def getExponent(self):
        return self._exp


if __name__ == '__main__':

    # data for unit tests
    m0 = Monomial(0, 1.0)  # a constant 1.0
    m1 = Monomial(1, 1.1)  # a linear term
    m2 = Monomial(2, 2.2)  # a quadratic
    m3 = Monomial(3, 3.3+4j)  # a cubic with a complex coefficient

    def unittests():
        '''This is a good place to put tests that are needed for a full exercise
of this module's functionality, but are not good as tutorial examples in the
normal doctests.

        >>> m2c = m2.clone()
        >>> print m2c
        2.2x^2
        >>> m2c.setCoefficient(-2.2)
        >>> print m2c
        -2.2x^2
        >>> m2c.setExponent(9)
        >>> print m2c
        -2.2x^9
        >>> print m2  # should be no change from original
        2.2x^2

        >>> mx = Monomial(exp=0, coeff=3)
        Traceback (most recent call last):
         - - -
        TypeError: coefficient must be float or complex

        >>> mx = Monomial(exp=2.1)
        Traceback (most recent call last):
         - - -
        TypeError: exp must be int or long
        
        >>> mx = Monomial(exp=-2)
        Traceback (most recent call last):
         - - -
        ValueError: exp must be non-negative
    
        >>> m2c.setCoefficient('a string')                          # [2]
        Traceback (most recent call last):
         - - -
        AssertionError
        >>> m2c.setExponent(-9)
        Traceback (most recent call last):
         - - -
        AssertionError
        '''
        
    from doctest import testmod
    testmod(verbose=True)

''' Notes
[1] Type checking is easy when needed, not required otherwise.  Good idea to do
it wherever user input might store bad data.

[2] assert is simple, but less informative than a special error message.

'''
